/*
 * @Author: liuzelin
 * @Date: 2024-04-14 12:23:45
 * @LastEditors: liuzelin
 * @LastEditTime: 2024-05-12 21:28:11
 * @Description: file content
 */
#include "panda_uv_helper.hpp"

#include "panda_log.hpp"
#include "panda_resolver_impl.hpp"
#include "panda_socket_impl.hpp"
#include "panda_thread_impl.hpp"

using namespace PandaImpl;

namespace {
Panda::SocketAddress GetPandaAddress(sockaddr_in* address) {
  char ip[128] = {0};
  uv_ip_name((const sockaddr*)address, ip, 128);
  return Panda::SocketAddress(ip, ntohs(address->sin_port));
}
}  // namespace

void UVHelper::UVCloseCb(uv_handle_t* handle) {
  UVHandler* h = (UVHandler*)uv_handle_get_data(handle);
  h->isClosed = true;
  h->isClosing = false;
  h->OnClose();
}

void UVHelper::UVOnAllocCb(uv_handle_t* handle, size_t size, uv_buf_t* buf) {
  SocketImpl* socket = (UDPSocketImpl*)uv_handle_get_data(handle);
  if (socket->buffer_) {
    free(socket->buffer_);
  }
  socket->buffer_ = (char*)malloc(size);
  *buf = uv_buf_init(socket->buffer_, size);
}

void UVHelper::UVReadCb(uv_stream_t* stream, ssize_t nread,
                        const uv_buf_t* buf) {
  TCPSocketImpl* socket =
      (TCPSocketImpl*)uv_handle_get_data((uv_handle_t*)stream);
  if (socket->listener_) {
    socket->listener_->OnRead(buf->base, nread);
  }
}

void UVHelper::UVConnectionCb(uv_stream_t* server, int status) {
  TCPSocketImpl* cli = (TCPSocketImpl*)ThreadManagerImpl::Instance()
                           ->Current()
                           ->CreateTCPSocket();
  TCPSocketImpl* s = (TCPSocketImpl*)uv_handle_get_data((uv_handle_t*)server);
  int ret = uv_accept((uv_stream_t*)server, (uv_stream_t*)&cli->socket_);
  PandaCheck(ret == 0) << " Ret:" << ret << " Error:" << uv_err_name(ret);
  if (s->listener_) {
    s->listener_->OnConnected(cli);
    cli->OnConnected();
  } else {
    delete cli;
  }
}

void UVHelper::UVConnectCb(uv_connect_t* req, int status) {
  TCPSocketImpl* socket = (TCPSocketImpl*)req->data;
  if (status == 0) {
    socket->OnConnected();
  } else {
    LOG(Warning) << "Connect To:" << socket->GetRemote().ToString()
                 << " Fail:" << status;
  }
}

void UVHelper::UVUdpRecvCb(uv_udp_t* handle, ssize_t nread, const uv_buf_t* buf,
                           const struct sockaddr* addr, unsigned flags) {
  UDPSocketImpl* socket =
      (UDPSocketImpl*)uv_handle_get_data((uv_handle_t*)handle);
  if (socket->listener_ && nread > 0) {
    Panda::SocketAddress remote(GetPandaAddress((sockaddr_in*)addr));
    socket->listener_->OnReadFrom(buf->base, nread, remote);
  }
}

void PandaImpl::UVHelper::UVOnUDPSendCb(uv_udp_send_t* req, int status) {
  UDPSendData* data = (UDPSendData*)req->data;
  if (status != 0) {
    if (data->socket->listener_)
      data->socket->listener_->OnSend(data->data, data->len, status,
                                      uv_err_name(status));
  } else {
    if (data->socket->listener_)
      data->socket->listener_->OnSend(data->data, data->len, 0, "");
  }

  if (data->socket->bind_address_ == false) {
    data->socket->UpdateLocalAddress();
  }
  delete data;
}

void PandaImpl::UVHelper::UVOnTCPSendCb(uv_write_t* req, int status) {
  TCPSendData* data = (TCPSendData*)req->data;
  data->socket->listener_->OnSend(data->data, data->len, status);
  delete data;
}

void UVHelper::UVTimerCb(uv_timer_t* handle) {
  UVTimer* t = (UVTimer*)uv_handle_get_data((uv_handle_t*)handle);
  if (t->onTimer_) {
    t->onTimer_(t);
  }
}

void UVHelper::UVAsyncCb(uv_async_t* handle) {
  UVAsync* e = (UVAsync*)uv_handle_get_data((uv_handle_t*)handle);
  e->thread_->Loop();
}

void PandaImpl::UVHelper::UVResolverCb(uv_getaddrinfo_t* req, int status,
                                       addrinfo* res) {
  ResolverImpl* resolver = (ResolverImpl*)req->data;
  resolver->OnResolverCb(req, status, res);
}
